/*
 * @title: 通用工具类
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-22 20:06:33
 * @LastEditors: andy.ten@tom.com
 * @LastEditTime: 2022-06-06 13:16:10
 * @version: 1.0.8
 * @copyright: copyright (c) 2022 andyten
 *  node: you can not copy and/or use and/or modify this program free,
 *  please reserve the segment above.Please mail me if you have any question.
 */
import { findImportTemplateInfo, download } from '@/api/ht.common';
import Hawthorn from 'hawthorn-ui/lib/hawthorn-ui.umd.min.js';
/**
 * @todo: 自定义error封装类
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-22 20:12:54
 * @param {*} message
 * @param {*} name
 */
export const MyError = function(message, name) {
  this.name = name || 'MyError';
  this.message = message || 'Default Message';
  this.stack = (new Error()).stack;
};
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;

// $eg.
// try {
//   throw new MyError('custom message');
// } catch (e) {
//   console.log(e.name);     // 'HtError'
//   console.log(e.message);  // 'custom message'
// }

/**
 * @todo: 验证是否是admin用户
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-04-06 12:41:49
 * @param {*} str
 */
export function isAdmin(str) {
  const valid_map = ['admin'];
  return valid_map.indexOf(str.trim()) >= 0;
};

/**
 * @todo: sessionStorage对象
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-22 20:44:39
 */
export const mySStorage = (function MySStorage() {
  const ms = 'myStorage';
  let mydata = '';
  const storage = window.sessionStorage;
  if (!storage) {
    alert('浏览器不支持sessionStorage');
    return false;
  }
  const set = (key, value) => {
    // 存储
    mydata = storage.getItem(ms);
    if (!mydata) {
      init();
      mydata = storage.getItem(ms);
      mydata = JSON.parse(mydata);
    } else mydata = JSON.parse(mydata);
    mydata[key] = value;
    storage.setItem(ms, JSON.stringify(mydata));
    return mydata;
  };

  const get = (key) => {
    // 读取
    if (!mydata) {
      mydata = storage.getItem(ms);
      mydata = JSON.parse(mydata);
    }
    return mydata === null ? '' : mydata[key];
  };

  var remove = (key) => {
    // 读取
    if (!mydata)
      return false;

    delete mydata[key];
    storage.setItem(ms, JSON.stringify(mydata));
    return mydata;
  };

  var clear = () => {
    // 清除对象
    storage.removeItem(ms);
  };

  var init = () => {
    storage.setItem(ms, '{}');
  };

  return {
    set: set,
    get: get,
    remove: remove,
    init: init,
    clear: clear
  };
})();

/**
 * @todo: localStorage对象
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-22 20:41:10
 */
export const myLStorage = (function MyLStorage() {
  var ms = 'myStorage';
  var mydata = '';
  var storage = window.localStorage;
  if (!storage) {
    alert('浏览器不支持localStorage');
    return false;
  }
  const set = (key, value) => {
    // 存储
    mydata = storage.getItem(ms);
    if (!mydata) {
      init();
      mydata = storage.getItem(ms);
      mydata = JSON.parse(mydata);
    } else mydata = JSON.parse(mydata);
    mydata[key] = value;
    storage.setItem(ms, JSON.stringify(mydata));
    return mydata;
  };

  const get = (key) => {
    // 读取
    if (!mydata) {
      mydata = storage.getItem(ms);
      mydata = JSON.parse(mydata);
    }
    return mydata == null ? '' : mydata[key];
  };

  const remove = (key) => {
    // 读取
    if (!mydata)
      return false;

    delete mydata[key];
    storage.setItem(ms, JSON.stringify(mydata));
    return mydata;
  };

  const clear = () => {
    // 清除对象
    storage.removeItem(ms);
  };

  const init = () => {
    storage.setItem(ms, '{}');
  };

  return {
    set: set,
    get: get,
    remove: remove,
    init: init,
    clear: clear
  };
})();

/**
 * @todo: sleep等待异步方法
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-22 20:17:43
 * @param {*} timeLen
 */
export const sleep = async(timeLen) => {
  return new Promise((resolve) => setTimeout(resolve, timeLen));
};
/**
 * @todo: 判断是否是string
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-04-06 12:49:51
 * @param {*} str
 */
export const isString = function(str) {
  if (typeof str === 'string' || str instanceof String)
    return true;
  return false;
};

/**
 * @todo: 判断是否是array
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-04-06 12:50:04
 * @param {*} arg
 */
export const isArray = function(arg) {
  if (typeof Array.isArray === 'undefined')
    return Object.prototype.toString.call(arg) === '[object Array]';

  return Array.isArray(arg);
};
/**
 * @todo: 防抖函数（一段时间内只响应最后一次操作，如：input框输入）
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-04-05 18:51:05
 * @param {*} func
 * @param {*} wait
 * @param {*} immediate
 */
export const debounce = function(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0)
      timeout = setTimeout(later, wait - last);
    else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function(...args) {
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
};
/**
 * @todo: 下载excel导入模版
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-06-05 21:33:51
 * @param {*} fileName
 */
export const downloadTemplate = async function(fileName) {
  if (!fileName) {
    Hawthorn.Notify.message('参数错误：需指定模版名称', 'error');
    return;
  }
  // 查询fuuid
  await findImportTemplateInfo(fileName).then((res) => {
    // console.log(res);
    if (res && res.datas && res.datas.file_uuid) {
      const p = { folder: 'true@importTemplate', isHoldName: 'true' };
      p['fuuid'] = res.datas.file_uuid;
      p['fileName'] = fileName;
      download(p).then((res) => {
        // 设置下载按钮状态
        if (res && res.data) {
          const fileName = decodeURI(res.headers['content-disposition'].split(';')[1].split('=')[1]);
          const blob = new Blob([res.data], {
            type: 'application/octet-stream'
          });
          const url = window.URL.createObjectURL(blob);
          const link = document.createElement('a');
          link.style.display = 'none';
          link.href = url;
          link.setAttribute('download', fileName);
          document.body.appendChild(link);
          // 兼容ie
          if (!!window.ActiveXObject || 'ActiveXObject' in window)
            window.navigator.msSaveOrOpenBlob(blob, link.download);
          else
            link.click();
          link.remove();
          window.URL.revokeObjectURL(url);
          Hawthorn.Notify.message('导入模版下载成功', 'success');
        } else
          Hawthorn.Notify.message('模版下载失败: 返回数据不正确', 'error');
      });
    } else
      Hawthorn.Notify.message('模版下载失败: 返回数据不正确', 'error');
  });
};

/**
 * @todo: 驼峰转换下划线
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-04-06 13:52:57
 * @param {*} name
 */
export const toLine = function(name) {
  return name.replace(/([A-Z])/g, '_$1').toLowerCase();
};

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export const hasClass = function(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
};

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export const addClass = function(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls;
};

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export const removeClass = function(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
    ele.className = ele.className.replace(reg, ' ');
  }
};

/**
 * @todo: 解决keep-alive include无法缓存问题
 * <p> keep-alive只缓存到第一层，也就是<HtRouteView/>这个组件，而这个组件只是一个<router-view/>组件</p>
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2022-03-31 13:05:55
 * @param {*} to
 */
export const handleKeepAlive = async(to) => {
  if (to.matched && to.matched.length > 2)
    for (let i = 0; i < to.matched.length; i++) {
      const element = to.matched[i];
      if (element.components.default.name === 'HtRouterView') {
        to.matched.splice(i, 1);
        await handleKeepAlive(to);
      }
      // fixme: js压缩完后name是x而不是HtRouterView 2022-04-13
      if (element.components.default.name.length < 3) {
        to.matched.splice(i, 1);
        await handleKeepAlive(to);
      }

      if (typeof element.components.default === 'function') { // 如果没有按需加载完成则等待加载
        await element.components.default();
        await handleKeepAlive(to);
      }
    }
};
